package com.ebupt.migu.fineoperationactivitymonitor.monitor.service.impl;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Service;

import com.ebupt.migu.fineoperationactivitymonitor.common.sms.Sender;
import com.ebupt.migu.fineoperationactivitymonitor.common.util.DateUtil;
import com.ebupt.migu.fineoperationactivitymonitor.monitor.entity.MonitoringThresholdsBean;
import com.ebupt.migu.fineoperationactivitymonitor.monitor.entity.OfflineActivityBean;
import com.ebupt.migu.fineoperationactivitymonitor.monitor.mapper.MonitorMapper;
import com.ebupt.migu.fineoperationactivitymonitor.monitor.service.MonitorService;

import lombok.extern.slf4j.Slf4j;

/**
 * @author liuyangyang@e-byte.com
 * @description: TODO
 * @date 2023/11/8 16:10
 */
@Slf4j
@Service
@EnableScheduling
public class MonitorServiceImpl implements MonitorService {

    @Autowired
    private MonitorMapper mapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${monitor.msisdn}")
    private String MSISDN;
    @Value("${system.sms.open}")
    private boolean OPEN;

    public static final String SMS_OFFLINE_SEND_MT = "SMS_OFFLINE_SEND_MT";
    public static final long SMS_OFFLINE_SEND_MT_DEF = 10 * 60 * 1000;
    public static final String SMS_OFFLINE_END_MT = "SMS_OFFLINE_END_MT";
    public static final long SMS_OFFLINE_END_MT_DEF = 2 * 60 * 60 * 1000;

    public static final String PUSH_OFFLINE_SEND_MT = "PUSH_OFFLINE_SEND_MT";
    public static final long PUSH_OFFLINE_SEND_MT_DEF = 10 * 60 * 1000;
    public static final String PUSH_OFFLINE_END_MT = "PUSH_OFFLINE_END_MT";
    public static final long PUSH_OFFLINE_END_MT_DEF = 2 * 60 * 60 * 1000;

    public static final String MESSAGE_OFFLINE_SEND_MT = "MESSAGE_OFFLINE_SEND_MT";
    public static final long MESSAGE_OFFLINE_SEND_MT_DEF = 10 * 60 * 1000;
    public static final String MESSAGE_OFFLINE_END_MT = "MESSAGE_OFFLINE_END_MT";
    public static final long MESSAGE_OFFLINE_END_MT_DEF = 2 * 60 * 60 * 1000;

    public static final String BANNER_OFFLINE_SEND_MT = "BANNER_OFFLINE_SEND_MT";
    public static final long BANNER_OFFLINE_SEND_MT_DEF = 10 * 60 * 1000;
    public static final String BANNER_OFFLINE_END_MT = "BANNER_OFFLINE_END_MT";
    public static final long BANNER_OFFLINE_END_MT_DEF = 2 * 60 * 60 * 1000;

    /**
     * 离线活动监控
     */
    @Override
    public void offlineActivityMonitor() {
        if (!DateUtil.belong()){
            log.info("监控时间为09:00 - 21:00，在此时段外不进行短信监控");
            return;
        }
        List<OfflineActivityBean> activities = mapper.offlineActivityMonitor();
        if (null == activities || 0 == activities.size()) {
            log.info("当前离线活动正常");
            return;
        }
        // 当前时间
        long now = System.currentTimeMillis();
        // 时间格式化
        DateFormat format = new SimpleDateFormat(DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
        for (OfflineActivityBean activity : activities) {
            log.info("当前活动：{}", activity.toString());
            // 判断当前活动今日是否下发过短信通知
            if (match(activity.getStrategyId(), 1, 1)) {
                log.info("当前活动今日已经下发过（结束时间延迟类）短信通知，不再重复通知：{}", activity.getStrategyId());
                continue;
            }
            // 获取不同类型活动的监控阈值
            MonitoringThresholdsBean mt = queryMTs(activity);
            try {
                // 任务类型：1-立即执行；2-单次执行；3-循环（重复）执行；4-间隔执行；
                switch (activity.getJobType()) {
                    case 1:
                        if (3 == activity.getExecuteStatus()) {
                            // 避免重复发送
                            if (match(activity.getStrategyId(), 0, 1)) {
                                log.info("当前活动今日已经下发过（触发时间延迟类）短信通知，不再重复通知：{}", activity.getStrategyId());
                                break;
                            }
                            long start = format.parse(activity.getCreateTime()).getTime();
                            if ((now - start) >= mt.getSendMT()) {
                                sendMessage(activity, 0);
                            }
                        }
                        if (4 == activity.getExecuteStatus() && 2 == activity.getExecuting()) {
                            long end = format.parse(activity.getExecuteTime()).getTime();
                            if ((now - end) >= mt.getEndMT()) {
                                sendMessage(activity, 1);
                            }
                        }
                        break;
                    case 2:
                        if (3 == activity.getExecuteStatus()) {
                            // 避免重复发送
                            if (match(activity.getStrategyId(), 0, 1)) {
                                log.info("当前活动今日已经下发过（触发时间延迟类）短信通知，不再重复通知：{}", activity.getStrategyId());
                                break;
                            }
                            long start = format.parse(activity.getStartTime()).getTime();
                            if ((now - start) >= mt.getSendMT()) {
                                sendMessage(activity, 0);
                            }
                        }
                        if (4 == activity.getExecuteStatus() && 2 == activity.getExecuting()) {
                            long end = format.parse(activity.getExecuteTime()).getTime();
                            if ((now - end) >= mt.getEndMT()) {
                                sendMessage(activity, 1);
                            }
                        }
                        break;
                    case 3:
                        if (3 == activity.getExecuteStatus()) {
                            // 避免重复发送
                            if (match(activity.getStrategyId(), 0, 1)) {
                                log.info("当前活动今日已经下发过（触发时间延迟类）短信通知，不再重复通知：{}", activity.getStrategyId());
                                break;
                            }
                            long start = format.parse(paresDate(activity.getStartTime())).getTime();
                            if ((now - start) >= mt.getSendMT()) {
                                sendMessage(activity, 0);
                            }
                        }
                        if (4 == activity.getExecuteStatus() && 2 == activity.getExecuting()) {
                            long end = format.parse(activity.getExecuteTime()).getTime();
                            if ((now - end) >= mt.getEndMT()) {
                                sendMessage(activity, 1);
                            }
                        }
                        break;
                    case 4:
                        // 判断今天是否应该执行
                        // 最近一次执行时间有记录
                        // 拼装间隔时间 long intervalTime = format.parse(activity.getExecuteTime()).getTime() +
                        // activity.getIntervalDays() * 24 * 60 * 60 * 1000;
                        // 判断当前时间是否大于间隔时间
                        if (StringUtils.isNotBlank(activity.getExecuteTime())
                            || (now - (format.parse(activity.getExecuteTime()).getTime()
                                + activity.getIntervalDays() * 24 * 60 * 60 * 1000)) < 0) {
                            log.info("当前活动今日未到达间隔触发时间：{}", activity.getStrategyId());
                            break;
                        }
                        if (3 == activity.getExecuteStatus()) {
                            // 避免重复发送
                            if (match(activity.getStrategyId(), 0, 1)) {
                                log.info("当前活动今日已经下发过（触发时间延迟类）短信通知，不再重复通知：{}", activity.getStrategyId());
                                break;
                            }
                            long start = format.parse(paresDate(activity.getStartTime())).getTime();
                            if ((now - start) >= mt.getSendMT()) {
                                sendMessage(activity, 0);
                            }
                        }
                        if (4 == activity.getExecuteStatus() && 2 == activity.getExecuting()) {
                            long end = format.parse(activity.getExecuteTime()).getTime();
                            if ((now - end) >= mt.getEndMT()) {
                                sendMessage(activity, 1);
                            }
                        }
                        break;
                    default:
                        log.error("当前活动不属于任何一种执行类型：1-立即执行；2-单次执行；3-循环（重复）执行；4-间隔执行；活动ID：{}", activity.getStrategyId());
                        break;
                }
            } catch (Exception e) {
                log.error("活动监控过程发生异常：{}, 异常信息：{}", activity.getStrategyId(), e.getMessage());
                e.printStackTrace();
            }
        }
    }

    /**
     * 将类型为iop标签与（咪咕音乐/视频彩铃）标签融合的客群状态，从“已完成”调整至“更新中”，然后进行客群融合。
     */
    @Override
    public void iopCustomerStatusCTRL() {
        mapper.iopCustomerStatusCTRL();
    }

    /**
     * iop标签客群与（咪咕音乐/视频彩铃）标签客群进行融合
     */
    @Override
    public void integrate() {
        // 仅iop标签的客群，如果临时客群创建完成，将客群状态调整至已完成
        List<String> list = mapper.iopCustomersOnly();
        for (String customerId : list) {
            // 判断临时客群是否已经创建完成（融合的前置条件）
            if (mapper.iopDone(customerId)) {
                // 融合完成后将客群状态修改至已完成
                // TODO 把蒋礼生成的客群id更名成标准名称——redis
                redisTemplate.rename(customerId + "-uid-iop", customerId + "-uid");
                redisTemplate.rename(customerId + "-phone-iop", customerId + "-phone");
                Map map = new HashMap<>();
                map.put("customerId", customerId);
                mapper.updateIopCustomerStatus(map);
            }
        }

        // iop标签与（咪咕音乐/视频彩铃）标签融合的客群，在融合完成后将客群状态调整至已完成
        List<String> dynamics = mapper.iopCustomers();
        for (String customerId : dynamics) {
            // 判断临时客群是否已经创建完成（融合的前置条件）
            if (mapper.iopDone(customerId)) {
                redisTemplate.rename(customerId + "-uid", customerId + "-uid-dxj");
                redisTemplate.rename(customerId + "-phone", customerId + "-phone-dxj");
                // TODO 进行客群融合
                Long uid = redisTemplate.opsForZSet().intersectAndStore(customerId + "-uid-iop", customerId + "-dxj",
                    customerId + "-uid");
                Long phone = redisTemplate.opsForZSet().intersectAndStore(customerId + "-phone-iop",
                    customerId + "-dxj", customerId + "-phone");

                redisTemplate.opsForZSet().remove(customerId + "-uid-dxj");
                redisTemplate.opsForZSet().remove(customerId + "-phone-dxj");

                Map map = new HashMap<>();
                map.put("customerId", customerId);
                map.put("clientUser", uid);
                map.put("mobileUser", phone);
                map.put("deviceUser", 0);
                map.put("userGroupSize", uid > phone ? uid : phone);
                // 融合完成后将客群状态修改至已完成
                mapper.updateIopCustomerStatus(map);
            }
        }
    }

    /**
     * 获取不同触点的通知时间阈值
     * 
     * @param activity
     * @return
     */
    public MonitoringThresholdsBean queryMTs(OfflineActivityBean activity) {
        MonitoringThresholdsBean mt = new MonitoringThresholdsBean();
        // 获取不同类型的活动的阈值时间
        // 策略类型：1-短信策略；2-banner策略；3-音乐之声策略；4-push策略；5-弹窗策略；6-消息通知；
        switch (activity.getStrategyType()) {
            case 1:
                mt.setSendMT(mts(SMS_OFFLINE_SEND_MT, SMS_OFFLINE_SEND_MT_DEF));
                mt.setEndMT(mts(SMS_OFFLINE_END_MT, SMS_OFFLINE_END_MT_DEF));
                break;
            case 2:
            case 3:
                mt.setSendMT(mts(BANNER_OFFLINE_SEND_MT, BANNER_OFFLINE_SEND_MT_DEF));
                mt.setEndMT(mts(BANNER_OFFLINE_END_MT, BANNER_OFFLINE_END_MT_DEF));
                break;
            case 4:
                mt.setSendMT(mts(PUSH_OFFLINE_SEND_MT, PUSH_OFFLINE_SEND_MT_DEF));
                mt.setEndMT(mts(PUSH_OFFLINE_END_MT, PUSH_OFFLINE_END_MT_DEF));
                break;
            case 6:
                mt.setSendMT(mts(MESSAGE_OFFLINE_SEND_MT, MESSAGE_OFFLINE_SEND_MT_DEF));
                mt.setEndMT(mts(MESSAGE_OFFLINE_END_MT, MESSAGE_OFFLINE_END_MT_DEF));
                break;
            default:
                mt.setSendMT(10 * 60 * 1000);
                mt.setEndMT(2 * 60 * 60 * 1000);
                break;
        }
        log.info("当前活动：{}，监控阈值信息：{}", activity.getStrategyId(), mt.toString());
        return mt;
    }

    /**
     * 获取redis中的默认值
     * 
     * @param key
     * @param def
     * @return
     */
    private long mts(String key, long def) {
        return redisTemplate.hasKey(key) ? Long.getLong(String.valueOf(redisTemplate.opsForValue().get(key))) : def;
    }

    /**
     * 构造短信模板
     * 
     * @param type 0-未按时开始 1-未按时结束
     * @return
     */
    private void sendMessage(OfflineActivityBean activity, int type) {
        String[] params = new String[3];
        params[0] = activity.getStrategyName();
        // 策略类型：1-短信策略；2-banner策略；3-音乐之声策略；4-push策略；5-弹窗策略；6-消息通知；
        switch (activity.getStrategyType()) {
            case 1:
                params[1] = "短信";
                break;
            case 2:
                params[1] = "BANNER";
                break;
            case 3:
                params[1] = "音乐之声";
                break;
            case 4:
                params[1] = "PUSH";
                break;
            case 6:
                params[1] = "消息通知";
                break;
        }
        StringBuffer str = new StringBuffer();
        str.append("预定执行时间为");
        // 任务类型：1-立即执行；2-单次执行；3-循环（重复）执行；4-间隔执行；
        switch (activity.getJobType()) {
            case 1:
                str.append(activity.getCreateTime());
                break;
            case 2:
                str.append(activity.getStartTime());
                break;
            case 3:
            case 4:
                str.append(paresDate(activity.getStartTime()));
                break;
        }
        // 0-未按时开始 1-未按时结束
        if (0 == type) {
            str.append("的活动未按时开始");
        }
        if (1 == type) {
            str.append("的活动已超出预计下发完成时间");
        }
        params[2] = String.valueOf(str);
        // 短信接收人
        String msisdns = MSISDN + "," + activity.getCreatorPhone();
        String[] tels = msisdns.split(",");
        Sender.sendSMS("20100066", tels, params);
        // 记录下发数据，避免当日重复发送
        // 0-未按时开始 1-未按时结束
        if (0 == type) {
            match(activity.getStrategyId(), 0, 0);
        }
        if (1 == type) {
            match(activity.getStrategyId(), 1, 0);
        }
    }

    /**
     * 时间转换
     * 
     * @param startTime
     * @return
     */
    private static String paresDate(String startTime) {
        DateFormat dateFormat = new SimpleDateFormat(DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
        Calendar startC = Calendar.getInstance();
        Calendar calendar = Calendar.getInstance();
        try {
            startC.setTime(dateFormat.parse(startTime));
            startC.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
            startC.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
            startC.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));
            String parse = dateFormat.format(startC.getTime());
            return parse;
        } catch (Exception e) {
            log.error("日期转换异常：{}", e.getMessage());
            return startTime;
        }
    }

    /**
     * 
     * @param activityId
     * @param type 0- 下发；1- 结束；
     * @param method 0- 写入； 1- 查询；
     * @return
     */
    private boolean match(String activityId, int type, int method) {
        // 测试环境不生成短信下发记录
        if (!OPEN) {
            return OPEN;
        }
        DateFormat format = new SimpleDateFormat(DateUtil.DATE_FORMAT_YYYYMMDD);
        String today = format.format(new Date());
        // Redis key
        String send = "OFFLINE_ACTIVITY_MONITOR_SEND_" + today;
        String end = "OFFLINE_ACTIVITY_MONITOR_END_" + today;
        // 创建当日redis集合并设置过期时间
        if (!redisTemplate.hasKey(send)) {
            redisTemplate.opsForSet().add(send, "CREATE");
            redisTemplate.expire(send, 24 * 60 * 60 * 1000, TimeUnit.MILLISECONDS);
        }
        if (!redisTemplate.hasKey(end)) {
            redisTemplate.opsForSet().add(end, "CREATE");
            redisTemplate.expire(end, 24 * 60 * 60 * 1000, TimeUnit.MILLISECONDS);
        }
        boolean res = true;
        switch (method) {
            case 0:
                // 下发写入
                if (0 == type) {
                    redisTemplate.opsForSet().add(send, activityId);
                }
                // 结束写入
                if (1 == type) {
                    redisTemplate.opsForSet().add(end, activityId);
                }
                break;
            case 1:
                // 下发查询
                if (0 == type) {
                    res = redisTemplate.opsForSet().isMember(send, activityId);
                }
                // 结束查询
                if (1 == type) {
                    res = redisTemplate.opsForSet().isMember(end, activityId);
                }
                break;
            default:
                res = false;
        }
        return res;
    }

    public static void main(String[] args) throws ParseException {
        System.out.println(DateUtil.belong());
    }
}
